package com.ktkj.init.annotation;

import com.alibaba.fastjson.JSON;
import com.ktkj.init.entity.LogInfo;
import com.ktkj.init.entity.UserInfo;
import com.ktkj.init.service.LogInfoService;
import com.ktkj.init.utils.IPUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.SecurityUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;

/**
 * 用于记录日志的切面.
 *
 * @author :yanlixiong
 * @date :2021-07-16 16:50:23
 */
@Component
@Aspect
@Slf4j
public class LogAspect {

    @Resource
    private LogInfoService logInfoService;

    /**
     * 注解Pointcut切入点
     * 定义出一个或一组方法，当执行这些方法时可产生通知
     * 指向你的切面类方法
     * 由于这里使用了自定义注解所以指向你的自定义注解
     */
    @Pointcut("@annotation(com.ktkj.init.annotation.Log)")
    public void logPointCut() {
    }

    /**
     * 使用环绕通知
     */
    @Around("logPointCut()")
    public Object around(ProceedingJoinPoint point) throws Throwable {
        long beginTime = System.currentTimeMillis();
        Object result = point.proceed();
        //执行时长(毫秒)
        long time = System.currentTimeMillis() - beginTime;
        //异步保存日志
        saveLog(point, time);
        return result;
    }

    public void saveLog(ProceedingJoinPoint joinPoint, long time) {
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();
        LogInfo logInfo = new LogInfo();
        //获取方法上的自定义注解
        Log log = method.getAnnotation(Log.class);
        if (log != null) {
            // 注解上的描述
            logInfo.setOperation(log.value());
        }
        //请求的方法名
        String className = joinPoint.getTarget().getClass().getName();
        String methodName = signature.getName();
        logInfo.setMethod(className + "." + methodName + "()");
        //获取request
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder
                .getRequestAttributes()).getRequest();
        //请求的参数
        logInfo.setParams(JSON.toJSONString(request.getParameterMap()));
        //设置IP地址
        logInfo.setIp(IPUtils.getIpAddr(request));
        //用户信息
        UserInfo userInfo = (UserInfo) SecurityUtils.getSubject().getPrincipal();
        logInfo.setUserId(userInfo != null ? userInfo.getId() : null);
        //用时
        logInfo.setTime(time);
        logInfoService.saveOrUpdate(logInfo);
    }
}
